#pragma once

#include<iostream>
#include<pthread.h>
#include<string>
#include<cstdio>
#include<cstring>

using namespace std;

typedef void*(*func_t)(void*); 

typedef enum
{
  NEW = 0,
  RUNNING,
  EXIT
}ThreadStatus;

class Thread
{
public:
  Thread(int num,func_t func,void* args)
    :_thread(0)
    ,_func(func)
    ,_args(args)
    ,_status(NEW)
  {
    char buffer[24];
    snprintf(buffer,sizeof(buffer),"thread->%d",num);
    _name = buffer;
  }
  
  int status() {return _status;}

  string& name() {return _name;}

  pthread_t thread()
  {
    if(_thread != 0)
    {
      return _thread;
    }
    else
    {
      cout << "This thread is not running" << endl;
      return 0;
    }
  }

  static void* RunHelper(void* args)
  {
    Thread* This = static_cast<Thread*>(args);
    (*This)();
    return nullptr;
  }

  void operator()()
  {
    _func(_args);
  }

  void run()
  {
    int n = pthread_create(&_thread,nullptr,RunHelper,this);
    if(n != 0)
    {
      cout << "creat occur error : " << strerror(n) << endl;
      exit(1);
    }
    _status = RUNNING;
  }

  void join()
  {
    int n = pthread_join(_thread,nullptr); 
    if(n != 0)
    {
      cout << "join occur error :  " << strerror(n) << endl;
      exit(2);
    }
    _status = EXIT;
  }

  ~Thread()
  {}
private: 
  pthread_t _thread;
  string _name;
  func_t _func; 
  void* _args;
  ThreadStatus _status;
};

